package cn.gok.gokhappymall.service.impl;

import cn.gok.gokhappymall.common.Const;
import cn.gok.gokhappymall.common.ServerResponse;
import cn.gok.gokhappymall.controller.vo.OrderItemVO;
import cn.gok.gokhappymall.controller.vo.OrderVO;
import cn.gok.gokhappymall.dao.*;
import cn.gok.gokhappymall.entity.*;
import cn.gok.gokhappymall.service.OrderService;
import cn.gok.gokhappymall.util.FTPUtil;
import com.alipay.api.AlipayResponse;
import com.alipay.demo.trade.model.ExtendParams;
import com.alipay.demo.trade.model.GoodsDetail;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.demo.trade.config.Configs;
import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.alipay.demo.trade.service.impl.AlipayMonitorServiceImpl;
import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;
import com.alipay.demo.trade.service.impl.AlipayTradeWithHBServiceImpl;
import com.alipay.demo.trade.utils.ZxingUtils;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

/**
 * @Author: chenfan
 * @Description:
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {


    @Autowired
    OrderMapper orderMapper;

    @Autowired
    OrderItemMapper orderItemMapper;

    @Autowired
    PayInfoMapper payInfoMapper;

    @Autowired
    CartMapper cartMapper;

    @Autowired
    ProductMapper productMapper;


    // 支付宝当面付2.0服务
    private static AlipayTradeService  tradeService;

    static {
        /** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数
         *  Configs会读取classpath下的zfbinfo.properties文件配置信息，如果找不到该文件则确认该文件是否在classpath目录
         */
        Configs.init("zfbinfo.properties");

        /** 使用Configs提供的默认参数
         *  AlipayTradeService可以使用单例或者为静态成员对象，不需要反复new
         */
        tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();
    }





    @Override
    @Transactional
    public ServerResponse<OrderVO> createOrder(Integer shippingId,Integer userId){

        //对购物车中处于已经选中的商品，进行下订单操作
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("cheked", 1);
        List<Cart> list = cartMapper.selectList(queryWrapper);

        //产生订单编号
        long oderNo = System.currentTimeMillis();
        
        //创建订单对象
        Order order = new Order();
        order.setOrderNo(oderNo);
        order.setUserId(userId);
        order.setShippingId(shippingId);
        order.setPaymentType(1);
        order.setPostage(0);
        order.setStatus(10);

        BigDecimal payment = new BigDecimal("0");


        //创建订单详情对象
        for (Cart cart : list) {
            Integer productId = cart.getProductId();
            Product product = productMapper.selectById(productId); //获取每个商品的信息
            Integer quantity = cart.getQuantity(); //对应商品的数量


            OrderItem orderItem = new OrderItem();
            orderItem.setOrderNo(oderNo);
            orderItem.setProductId(productId);
            orderItem.setProductName(product.getName());
            orderItem.setQuantity(quantity);
            orderItem.setCurrentUnitPrice(product.getPrice());
            orderItem.setProductImage(product.getMainImage());

            //计算购物车此种商品的总价
            BigDecimal multiply = product.getPrice().multiply(new BigDecimal(quantity));
            orderItem.setTotalPrice(multiply);

            //计算下单的总价，对下单的所有的商品的金额累加
            payment = payment.add(multiply);
            orderItemMapper.insert(orderItem);

        }
        order.setPayment(payment);
        int i = orderMapper.insert(order);


        //下单成功，构建响应结果集
        if (i > 0){
            OrderVO orderVO = new OrderVO();
            BeanUtils.copyProperties(order, orderVO);
            List<OrderItemVO> orderItemVOs = createOrderItemVOs(oderNo);
            orderVO.setOrderItemVoList(orderItemVOs);


            return ServerResponse.createBySuccess(orderVO);
        }

        return ServerResponse.createByErrorMessage("下单失败，请重试");

    }



    public List<OrderItemVO> createOrderItemVOs(Long orderNo){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("order_no", orderNo);
        List<OrderItemVO> orderItemVOS = new ArrayList<>();

        List<OrderItem> list = orderItemMapper.selectList(queryWrapper);
        for (OrderItem orderItem : list) {
            OrderItemVO orderItemVO = new OrderItemVO();
            BeanUtils.copyProperties(orderItem,orderItemVO);
            orderItemVOS.add(orderItemVO);
        }

        return  orderItemVOS;
    }




    @Override
    public ServerResponse alipayCallback(Map<String ,String> params){
        Long out_trade_no = Long.parseLong(params.get("out_trade_no"));//获取交易的订单号
        BigDecimal total_amount= new BigDecimal(params.get("total_amount")); //获取交易的金额

        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("order_no", out_trade_no);
        Order order = orderMapper.selectOne(queryWrapper);

        if (order == null){
            return ServerResponse.createByErrorMessage("订单编号不对，忽略此次支付");
        }

        if (!total_amount.equals(order.getPayment())){
            return ServerResponse.createByErrorMessage("此次订单支付金额不对，忽略此次支付");
        }


        String trade_status = params.get("trade_status"); //获取交易状态

        //判断根据支付宝返回的值，修改订单的交易状态 , 并且向支付信息表中存入支付信息数据
        if (trade_status.equals("TRADE_SUCCESS")){

            order.setStatus(Const.OrderStatusEnum.PAID.getCode());
            orderMapper.updateById(order);


            PayInfo payInfo = new PayInfo();
            payInfo.setOrderNo(out_trade_no);
            payInfo.setUserId(order.getUserId());
            payInfo.setPayPlatform(Const.PayPlatformEnum.ALIPAY.getCode());
            payInfo.setPlatformNumber(params.get("trade_no"));
            payInfo.setPlatformStatus(trade_status);

            int insert = payInfoMapper.insert(payInfo);

            return ServerResponse.createBySuccess();

        }
        return ServerResponse.createByError();
    }



    @Override
    public ServerResponse pay(Long orderNo, int userId,String filePath) throws IOException {

        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("order_no", orderNo);
        queryWrapper.eq("user_id", userId);
        Order order = orderMapper.selectOne(queryWrapper);

        if (order == null) {
            return ServerResponse.createByErrorMessage("该订单不存在，请重试");
        }


        Map<String, Object> params = new HashMap<>();
        params.put("order_no", orderNo);
        List<OrderItem> orderItems = orderItemMapper.selectByMap(params);


        // (必填) 商户网站订单系统中唯一订单号，64个字符以内，只能包含字母、数字、下划线，
        // 需保证商户系统端不能重复，建议通过数据库sequence生成，
        String outTradeNo = String.valueOf(orderNo);

        // (必填) 订单标题，粗略描述用户的支付目的。如“xxx品牌xxx门店当面付扫码消费”
        String subject = "xxx门店当面付扫码消费";

        // (必填) 订单总金额，单位为元，不能超过1亿元
        // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
        String totalAmount = String.valueOf(order.getPayment());

        // (可选) 订单不可打折金额，可以配合商家平台配置折扣活动，如果酒水不参与打折，则将对应金额填写至此字段
        // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
        String undiscountableAmount = "0";

        // 卖家支付宝账号ID，用于支持一个签约账号下支持打款到不同的收款账号，(打款到sellerId对应的支付宝账号)
        // 如果该字段为空，则默认为与支付宝签约的商户的PID，也就是appid对应的PID
        String sellerId = "";

        // 订单描述，可以对交易或商品进行一个详细地描述，比如填写"购买商品2件共15.00元"
        int quantity = 0;
        for (OrderItem orderItem : orderItems) {
            quantity += orderItem.getQuantity();
        }

        String body = "购买了" + quantity + "件商品，总价为：" + order.getPayment();

        // 商户操作员编号，添加此参数可以为商户操作员做销售统计
        String operatorId = "test_operator_id";

        // (必填) 商户门店编号，通过门店号和商家后台可以配置精准到门店的折扣信息，详询支付宝技术支持
        String storeId = "2088621955826460";

        // 业务扩展参数，目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法)，详情请咨询支付宝技术支持
        ExtendParams extendParams = new ExtendParams();
        extendParams.setSysServiceProviderId("2088100200300400500");

        // 支付超时，定义为120分钟
        String timeoutExpress = "120m";

        // 商品明细列表，需填写购买商品详细信息，
        List<GoodsDetail> goodsDetailList = new ArrayList<GoodsDetail>();

        for (OrderItem orderItem : orderItems) {
            // 创建一个商品信息，参数含义分别为商品id（使用国标）、名称、单价（单位为分）、数量，如果需要添加商品类别，详见GoodsDetail
            GoodsDetail goods = new GoodsDetail();
            goods.setGoodsId(String.valueOf(orderItem.getProductId()));
            goods.setGoodsName(orderItem.getProductName());

            //因为orderItem.getCurrentUnitPrice()得到是一个BigDecimal对象， 但是支付宝要求价格数据为分，所以乘100
            goods.setPrice(orderItem.getCurrentUnitPrice().multiply(new BigDecimal("100")).longValue());
            goods.setQuantity(orderItem.getQuantity());
            // 创建好一个商品后添加至商品明细列表
            goodsDetailList.add(goods);
        }


        // 创建扫码支付请求builder，设置请求参数
        AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
                .setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo)
                .setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body)
                .setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams)
                .setTimeoutExpress(timeoutExpress)
                .setNotifyUrl("http://cn-gok-happymall.natapp1.cc/order/alipay_callback.do")//支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置
                .setGoodsDetailList(goodsDetailList);


        AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
        switch (result.getTradeStatus()) {
            case SUCCESS:
                log.info("支付宝预下单成功: )");
                AlipayTradePrecreateResponse response = result.getResponse();
                dumpResponse(response);

                // 创建二维码文件的路径
                String erweimaPath = String.format(filePath + "/qr-%s.png",response.getOutTradeNo());
                log.info("filePath:" + filePath);
                //获取二维码的文件名，就是订单编号名
                String erweimaFileName = String.format("qr-%s.png",response.getOutTradeNo());
                // 通过支付宝提供的工具类，将二维码输出到指定为路径中
                ZxingUtils.getQRCodeImge(response.getQrCode(), 256, erweimaPath);


                //将二维码上传至ftp服务器
                FTPUtil ftpUtil = new FTPUtil();
                boolean isUploadFile = ftpUtil.uploadFile(new File(filePath, erweimaFileName));

                Map<String, Object> map = new HashMap();
                map.put("orderNo",response.getOutTradeNo()); //返回订单号
                map.put("qrPath","ftp://localhost:21/img"+ File.separator +erweimaFileName);//返回二维码图片在ftp服务中的位置
                return  ServerResponse.createBySuccess(map);

            case FAILED:
                log.error("支付宝预下单失败!!!");
                return ServerResponse.createByErrorMessage("支付宝预下单失败!!!");

            case UNKNOWN:
                log.error("系统异常，预下单状态未知!!!");
                return ServerResponse.createByErrorMessage("支系统异常，预下单状态未知!!!");

            default:
                log.error("不支持的交易状态，交易返回异常!!!");
                return ServerResponse.createByErrorMessage("不支持的交易状态，交易返回异常!!!");

        }

    }

    // 简单打印应答
    private void dumpResponse(AlipayResponse response) {
        if (response != null) {
            log.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg()));
            if (StringUtils.isNotEmpty(response.getSubCode())) {
                log.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(),
                        response.getSubMsg()));
            }
            log.info("body:" + response.getBody());
        }
    }

}
